//
// SecantMethod.cpp
// Secant method implementation.
//
// Author: Gabriel H. Barbuto (gbarbuto@dc.uba.ar)
//
#include <cmath>
#include <cstddef>
#include <functional>
#include <vector>

#include "BinaryIterativeMethod.h"
#include "SecantMethod.h"

SecantMethod::SecantMethod(std::function<double(double)> const &f, std::size_t const &iterations) :
BinaryIterativeMethod(iterations), _f(f)
{
}

SecantMethod::SecantMethod(std::function<double(double)> const &f, double const &epsilon, std::size_t const &iterations) :
BinaryIterativeMethod(epsilon, iterations), _f(f)
{
}

double SecantMethod::operator()(std::vector<double> const &arguments)
{
	this->check(arguments);

	double x_2(0.0);
	double x(arguments[1]);
	double x_1(arguments[0]);

	double fx((this->_f)(x_1));

	std::function<double(double)> const &f(this->_f);

	std::function<double(double, double, double, double)> const secant_function(
		[](double const &x, double const &x_1, double const &fx, double const &fx_1)
		{
			return x - fx * (x - x_1) / (fx - fx_1);
		}
	);

	for (std::size_t iteration(0); iteration < this->max_iterations(); ++iteration)
	{
		x_2 = x_1;
		x_1 = x;

		double fx_1(fx);
		fx = f(x_1);

		x = secant_function(x_1, x_2, fx, fx_1);

		if (std::fabs(x - x_1) < this->epsilon())
		{
			this->iterations(iteration);

			return x;
		}
	}

	this->iterations(this->max_iterations());

	return x;
}
